/*******************************************************************************
 * Copyright (c) 2001, 2002 Boris Pruessmann and others. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Common Public License v0.5 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.core.internal.utils;

import com.google.common.collect.Lists;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.PerforceException;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.Status;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.List;

/**
 * @version $Revision: 488 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris
 *         Pruessmann</a>
 */
public class MetaFileWriter {
  //----------------------------------------------------------------------------
  // Public Constants

  /** the local workspace file that contains pattern for ignored resources */
  public static final String IGNORE_FILE = ".p4ignore"; //$NON-NLS-1$

  /** key for saving the mod stamp for each writen meta file */
  public static final QualifiedName MODSTAMP_KEY =
      new QualifiedName("net.sourceforge.perforce.core", "meta-file-modtime"); //$NON-NLS-1$ //$NON-NLS-2$

  // -----------------------------------------------------------------------
  // Public Static Methods

  /**
   * Reads the ignore file for the given folder and returns its entries.
   * 
   * @param folder the folder.
   * @return the ignore entries.
   * @throws PerforceException in case of an error.
   */
  public static String[] readP4IgnoreEntries(IContainer folder) throws PerforceException {
    IFile ignoreFile = folder.getFile(new Path(IGNORE_FILE));
    if (ignoreFile != null) {
      return readLines(ignoreFile);
    }

    return null;
  }

  /**
   * Writes the ignore file for the given folder, storing the specified
   * patterns.
   * 
   * @param folder the folder in which the .p4ignore file is stored.
   * @param patterns the patterns to store.
   * @throws PerforceException in case of an error.
   */
  public static void writeP4IgnoreEntries(IContainer folder, String[] patterns)
      throws PerforceException {
    IFile ignoreFile = folder.getFile(new Path(IGNORE_FILE));
    writeLines(ignoreFile, patterns);
  }

  // ----------------------------------------------------------------------
  // Private Static Methods

  /**
   * Called to read the content of the given file.
   * 
   * @param file the to read.
   * @return the contents file.
   * @throws PerforceException in case of an error.
   */
  private static String[] readLines(IFile file) throws PerforceException {
    try {
      BufferedReader reader = new BufferedReader(new InputStreamReader(file.getContents()));
      List<String> fileContentStore = Lists.newArrayList();
      try {
        String line;
        while ((line = reader.readLine()) != null) {
          fileContentStore.add(line);
        }

        return fileContentStore.toArray(new String[fileContentStore.size()]);
      } finally {
        reader.close();
      }
    } catch (IOException e) {
      throw new PerforceException(new Status(Status.ERROR, PerforceCorePlugin.ID, -1, e
          .getMessage(), e));
    } catch (CoreException e) {
      if (e.getStatus().getCode() == IResourceStatus.RESOURCE_NOT_FOUND) {
        return null;
      }

      throw new PerforceException(e.getStatus());
    }
  }

  /**
   * Called to write the content of the given ignore file.
   * 
   * @param ignoreFile the file to write.
   * @param patterns the patterns to store.
   * @throws PerforceException in case of an error.
   */
  private static void writeLines(final IFile ignoreFile, final String[] patterns)
      throws PerforceException {
    try {
      ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() {
        public void run(IProgressMonitor monitor) throws CoreException {
          try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            writeLinesToStreamAndClose(os, patterns);
            if (!ignoreFile.exists()) {
              ignoreFile.create(new ByteArrayInputStream(os.toByteArray()), IResource.NONE, null);
            } else {
              ignoreFile.setContents(new ByteArrayInputStream(os.toByteArray()), IResource.NONE,
                  null);
            }

            ignoreFile
                .setSessionProperty(MODSTAMP_KEY, new Long(ignoreFile.getModificationStamp()));
          } catch (PerforceException e) {
            throw new CoreException(e.getStatus());
          }
        }
      }, null);
    } catch (CoreException e) {
      throw new PerforceException(e.getStatus());
    }
  }

  /**
   * Writes the given lines to the output stream, closing it at the end.
   * 
   * @param os the output stream.
   * @param patterns the patterns to write.
   * @throws PerforceException in case of an error.
   */
  private static void writeLinesToStreamAndClose(OutputStream os, String[] patterns)
      throws PerforceException {
    try {
      try {
        for (int i = 0; i < patterns.length; i++) {
          os.write(patterns[i].getBytes());
          os.write(0x0A);
        }
      } finally {
        os.close();
      }
    } catch (IOException e) {
      throw new PerforceException(new Status(Status.ERROR, PerforceCorePlugin.ID, -1, e
          .getMessage(), e));
    }
  }
}
